///////////////////////////////////////////////////////////////////////////////
//    Copyright (c) 2021 CASTest Corporation Limited. All Rights Reserved    //
///////////////////////////////////////////////////////////////////////////////

#include "Simulation.h"

void Simulation::ParseStilFile(const string& stil_file) {

    if (!Utils::CheckFileExist(stil_file)) {
        string msg = "no external stil file";
        cerr << Errors::ErrorsMsg(ErrorType::FILE_NOT_FOUND, msg) << endl;
        exit(1);
    }

    STILparser sp;
    sp.parse(stil_file);
    auto test_so_name = sp.GetStilSo();
    auto clks         = sp.GetStilClk();

    vector<int> test_so_id;
    for (int i = 0; i < _po.size() && test_so_id.size() < test_so_name.size(); ++i) {
        if (find(test_so_name.begin(), test_so_name.end(), _po[i]->GetName()) != test_so_name.end()) {
            test_so_id.push_back(_po[i]->GetId());
        }
    }
    // Trace scan chain
    TracePrimitiveScanChain(test_so_id, false);

    // Set signals
    _pattern_reader.SetNumPI(_num_pi);
    _pattern_reader.SetNumPo(_num_po);
    _pattern_reader.SetNumScanChain(_scan_chains.size());

    for (int i = 0; i < _pi.size() && _clock_pi_ids.size() <= clks.size(); ++i) {
        for (auto clk : clks) {
            if (clk.first == _pi[i]->GetName()) {
                _clock_pi_ids.push_back(_pi[i]->GetId());
                _pattern_reader._clock_pi_ids.push_back(_pi[i]->GetId());
                _pattern_reader._clock_start_value[_pi[i]->GetId()] = clk.second;
            }
        }
    }
    // Map stil and vy file pi order and Read pattern from stil file
    auto pi_order_map = _pattern_reader.CreateSignalOrderMap(_pi, sp.GetStilPi());
    auto po_order_map = _pattern_reader.CreateSignalOrderMap(_po, sp.GetStilPo());
    _pattern_reader.ReadPatternFromStil(stil_file, pi_order_map, po_order_map);
    _last_pattern_bit_num = _pattern_reader.ConvertSerialToParallelPattern();
}

void Simulation::AddActiveGateToEvents(Gate *gptr, EventContainer *events, int word_id) {
    for (auto output : gptr->GetAllFanouts()) {
        events->add(output, word_id);
    }
}

void Simulation::UpdateGateValue(Gate *gptr, int word_id, int frame_id, Value &new_value, EventContainer *events) {

    int gate_id = gptr->GetId();
    int store_value_frame_id = _gate_value_array_frame_ids[gate_id][word_id][frame_id];
    Value old_value = _logic_array[gate_id][word_id][store_value_frame_id];
    if (old_value != new_value) {
        _gate_value_array_frame_ids[gate_id][word_id][frame_id] = frame_id;
        if (frame_id == 1) {
            _gate_value_array_frame_ids[gate_id][word_id][2] = 1;
        }
        _logic_array[gate_id][word_id][frame_id] = new_value;
        AddActiveGateToEvents(gptr, events, word_id);
    }
}

void Simulation::EvalGateSim(Gate *gptr, const vector<int> &word_ids, int frame_id, EventContainer *events) {
    unsigned int type = gptr->GetLogicType();
    int fanin_size = gptr->GetFaninsSize();
    uint64_t w0, w1;
    Value new_value;
    vector<uint64_t> v0(4, 0);
    vector<uint64_t> v1(4, 0);
    int store_value_frame_id;
    assert(fanin_size > 0);
    switch (type) {
        case G_PO:
        case G_BUF:
        case G_BUF_ASSGIN:
        case G_STEM:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                new_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_NOT:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                new_value.bit0 = old_value.bit1;
                new_value.bit1 = old_value.bit0;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_AND:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                uint64_t a0 = old_value.bit0;
                uint64_t a1 = old_value.bit1;
                Value b;
                for (int fi = 1; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    b = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                    uint64_t b0 = b.bit0;
                    uint64_t b1 = b.bit1;
                    w0 = a0 & b0;
                    w1 = a1 | b1;
                    a0 = w0;
                    a1 = w1;
                }
                new_value.bit0 = a0;
                new_value.bit1 = a1;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_NAND:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                uint64_t a0 = old_value.bit0;
                uint64_t a1 = old_value.bit1;
                Value b;
                for (int fi = 1; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    b = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                    uint64_t b0 = b.bit0;
                    uint64_t b1 = b.bit1;
                    w0 = a0 & b0;
                    w1 = a1 | b1;
                    a0 = w0;
                    a1 = w1;
                }
                new_value.bit0 = a1;
                new_value.bit1 = a0;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_OR:
            for (auto word_id : word_ids) {

                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                uint64_t a0 = old_value.bit0;
                uint64_t a1 = old_value.bit1;
                Value b;
                for (int fi = 1; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    b = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                    uint64_t b0 = b.bit0;
                    uint64_t b1 = b.bit1;
                    w0 = a0 | b0;
                    w1 = a1 & b1;
                    a0 = w0;
                    a1 = w1;
                }
                new_value.bit0 = a0;
                new_value.bit1 = a1;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_NOR:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                uint64_t a0 = old_value.bit0;
                uint64_t a1 = old_value.bit1;
                Value b;
                for (int fi = 1; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    b = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                    uint64_t b0 = b.bit0;
                    uint64_t b1 = b.bit1;
                    w0 = a0 | b0;
                    w1 = a1 & b1;
                    a0 = w0;
                    a1 = w1;
                }
                new_value.bit0 = a1;
                new_value.bit1 = a0;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_XOR:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                uint64_t a0 = old_value.bit0;
                uint64_t a1 = old_value.bit1;
                Value b;
                for (int fi = 1; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    b = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                    uint64_t b0 = b.bit0;
                    uint64_t b1 = b.bit1;
                    w0 = ((a1 & b0) | (a0 & b1));
                    w1 = ((a1 & b1) | (a0 & b0));
                    a0 = w0;
                    a1 = w1;
                }
                new_value.bit0 = a0;
                new_value.bit1 = a1;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_XNOR:
            for (auto word_id : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                Value old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
                uint64_t a0 = old_value.bit0;
                uint64_t a1 = old_value.bit1;
                Value b;
                for (int fi = 1; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    b = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                    uint64_t b0 = b.bit0;
                    uint64_t b1 = b.bit1;
                    w0 = ((a1 & b0) | (a0 & b1));
                    w1 = ((a1 & b1) | (a0 & b0));
                    a0 = w0;
                    a1 = w1;
                }
                new_value.bit0 = a1;
                new_value.bit1 = a0;
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);
            }
            break;
        case G_MUX:
            for (auto p : word_ids) {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(1)->GetId()][p][frame_id];
                Value in0 = _logic_array[gptr->GetFanin(1)->GetId()][p][store_value_frame_id];
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(2)->GetId()][p][frame_id];
                Value in1 = _logic_array[gptr->GetFanin(2)->GetId()][p][store_value_frame_id];
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][p][frame_id];
                Value sel = _logic_array[gptr->GetFanin(0)->GetId()][p][store_value_frame_id];


                uint64_t se_not0 = sel.bit1;
                uint64_t se_not1 = sel.bit0;
                new_value.bit0 = ((se_not0 & in0.bit0) | (sel.bit0 & in1.bit0));;
                new_value.bit1 = ((se_not1 | in0.bit1) & (sel.bit1 | in1.bit1));;
                UpdateGateValue(gptr, p, frame_id, new_value, events);
            }
            break;
        case G_DFF: {
            uint64_t set0, set1, reset0, reset1, clock0, clock1, data_in0, data_in1;


            for (auto word_id : word_ids) {
                assert(fanin_size == 4);
                for (int fi = 0; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    v0[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit0;
                    v1[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit1;
                }

                set0 = v0[0];
                set1 = v1[0];

                reset0 = v0[1];
                reset1 = v1[1];

                clock0 = v0[2];
                clock1 = v1[2];

                data_in0 = v0[3];
                data_in1 = v1[3];
                int dff_gate_id = gptr->GetId();
                assert(_dff_gate_id_to_master_map.count(dff_gate_id));
                int dff_master_id = _dff_gate_id_to_master_map[dff_gate_id];

                Value master_hold_value;
                master_hold_value = _dff_master_logic_array[dff_master_id][word_id];
                Value master_new_value;


                master_new_value.bit0 = ((~clock0) & clock1 & data_in0) | ((~clock1) & clock0 & master_hold_value.bit0);
                master_new_value.bit1 = ((~clock0) & clock1 & data_in1) | ((~clock1) & clock0 & master_hold_value.bit1);


                master_new_value.bit0 = ((~set0) & set1 & master_new_value.bit0) | ((~set1) & set0);
                master_new_value.bit1 = ((~set0) & set1 & master_new_value.bit1);


                master_new_value.bit0 = ((~reset0) & reset1 & master_new_value.bit0);
                master_new_value.bit1 = ((~reset0) & reset1 & master_new_value.bit1) | ((~reset1) & reset0);


                Value slave_hold_value;
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetId()][word_id][frame_id];
                slave_hold_value = _logic_array[gptr->GetId()][word_id][store_value_frame_id];
                Value slave_new_value;



                slave_new_value.bit0 =
                        ((~clock1) & clock0 & master_hold_value.bit0) | ((~clock0) & clock1 & slave_hold_value.bit0);
                slave_new_value.bit1 =
                        ((~clock1) & clock0 & master_hold_value.bit1) | ((~clock0) & clock1 & slave_hold_value.bit1);


                slave_new_value.bit0 = ((~set0) & set1 & slave_new_value.bit0) | ((~set1) & set0);
                slave_new_value.bit1 = ((~set0) & set1 & slave_new_value.bit1);


                slave_new_value.bit0 = ((~reset0) & reset1 & slave_new_value.bit0);
                slave_new_value.bit1 = ((~reset0) & reset1 & slave_new_value.bit1) | ((~reset1) & reset0);


                _dff_master_logic_array[dff_master_id][word_id] = master_new_value;
                UpdateGateValue(gptr, word_id, frame_id, slave_new_value, events);

            }
            break;


        }
        case G_DLAT: {
            uint64_t set0, set1, reset0, reset1, clock0, clock1, data_in0, data_in1;
            for (auto word_id : word_ids) {
                assert(fanin_size == 4);
                for (int fi = 0; fi < fanin_size; fi++) {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    v0[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit0;
                    v1[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit1;
                }

                set0 = v0[0];
                set1 = v1[0];

                reset0 = v0[1];
                reset1 = v1[1];

                clock0 = v0[2];
                clock1 = v1[2];

                data_in0 = v0[3];
                data_in1 = v1[3];
                int dlat_gate_id = gptr->GetId();

                Value hold_value;
                store_value_frame_id = _gate_value_array_frame_ids[dlat_gate_id][word_id][frame_id];
                hold_value = _logic_array[dlat_gate_id][word_id][store_value_frame_id];

                new_value.bit0 = ((~clock0) & clock1 & hold_value.bit0) | ((~clock1) & clock0 & data_in0);
                new_value.bit1 = ((~clock0) & clock1 & hold_value.bit1) | ((~clock1) & clock0 & data_in1);

                new_value.bit0 = ((~set0) & set1 & new_value.bit0) | ((~set1) & set0);
                new_value.bit1 = ((~set0) & set1 & new_value.bit1);

                new_value.bit0 = ((~reset0) & reset1 & new_value.bit0);
                new_value.bit1 = ((~reset0) & reset1 & new_value.bit1) | ((~reset1) & reset0);
                UpdateGateValue(gptr, word_id, frame_id, new_value, events);


            }
            break;
        }
        default: {
            string msg = "not support logic type: " + to_string(type);
            cerr << Errors::ErrorsMsg(ErrorType::INVALID, msg) << endl;
            exit(1);
        }
    }
}

void
Simulation::SetPattern(const vector<vector<Value>> &serial_patterns,
                       const vector<vector<vector<Value>>> &load_values,
                       EventContainer *events, size_t pattern_id, size_t logic_array_id) {
    // set load value
    int pattern_num = serial_patterns.size();
    auto &pattern = serial_patterns[pattern_id];
    for (int pi_id = 0; pi_id < pattern.size(); pi_id++) {
        Gate *pi_gptr = _pi[pi_id];
        Value gate_value = pattern[pi_id];
        UpdateGateValue(pi_gptr, pattern_id, logic_array_id, gate_value, events);
    }


    // set supply value
    Value supply1_value;
    Value supply0_value;
    if(!_is_parallel_pattern){
        supply0_value.SetSerial0();
        supply1_value.SetSerial1();
    }else{
        if(pattern_id == _pi_value_size - 1){
            supply0_value.SetParallel0(_last_pattern_bit_num);
            supply1_value.SetParallel1(_last_pattern_bit_num);
        }else{
            supply0_value.SetParallel0(SIZE_OF_PACKET);
            supply1_value.SetParallel1(SIZE_OF_PACKET);
        }
    }

    for (int i = 0; i < _supply.size(); i++) {
        auto supply_gptr = _supply[i];
        if (supply_gptr->GetLogicType() == G_SUPPLY0) {
            UpdateGateValue(supply_gptr, pattern_id, logic_array_id, supply0_value, events);
        } else {
            UpdateGateValue(supply_gptr, pattern_id, logic_array_id, supply1_value, events);
        }

    }
    // set scan_chain value
    for (size_t i = 0; i < _scan_chains.size(); i++) {
        for (size_t j = 0; j < _scan_chains[i].size(); j++) {
            auto dff_gptr = _scan_chains[i][j];
            auto dff_value = load_values[pattern_id][i][j];
            auto dff_id = dff_gptr->GetId();
            auto dff_master_id = _dff_gate_id_to_master_map[dff_id];
            _dff_master_logic_array[dff_master_id][pattern_id] = dff_value;
            UpdateGateValue(dff_gptr, pattern_id, logic_array_id, dff_value, events);

        }
    }
}

bool Simulation::LogicSim(size_t start_pattern_id, size_t end_pattern_id, EventContainer *events) {


    for (int pattern_id = start_pattern_id; pattern_id < end_pattern_id; ++pattern_id) {
        // cout << "start sim pattern id" << pattern_id << endl;
        // InitSerialLogicArray(logic_array_id, events);
        // frame1 set pi value, set clock value = 0
        SetPattern(_pi_value, _load_value, events, pattern_id, 0);
        Value clock_value;
        // PrintSerialScanChainsValue(pattern_id);
        for (int frame = 0; frame <= 2; frame++) {

            for(int i =0; i < _clock_pi_ids.size(); i++){
                int clock_gate_pi_id = _clock_pi_ids[i];
                auto clock_gptr = _pi[clock_gate_pi_id];
                if(frame == 1){
                    clock_value = _pattern_clock_value[pattern_id][i];
                }else{
                    clock_value = _pi_value[pattern_id][clock_gate_pi_id];
                }

                UpdateGateValue(clock_gptr, pattern_id, frame, clock_value, events);
            }

            Gate *active_gptr = nullptr;
            vector<int> active_words;
            active_words.push_back(pattern_id);
            events->next(active_gptr, active_words);
            while (active_gptr) {
                EvalGateSim(active_gptr, active_words, frame, events);
                events->next(active_gptr, active_words);
            }
            if (frame == 0) {
                bool success = CompareLogicSimPo(_po_value, pattern_id, frame);
                if (!success) {
                    string msg = "wrong pattern_id" + pattern_id;
                    cerr << Errors::ErrorsMsg(ErrorType::LSIM_RUN_FAILED, msg) << endl;
                    assert(false);
                }
            }
        }
//        PrintSerialScanChainsValue(pattern_id);
        bool success = CompareLogicSimScanChain(_unload_value, pattern_id, 2);
        assert(success);
        // cout << "end" << endl;

    }
    return true;
}

void Simulation::AllocLogicArray(int num_pattern) {
    _logic_array.clear();
    _gate_value_array_frame_ids.clear();
    _logic_array = vector<vector<vector<Value>>>(_num_net, vector<vector<Value>>(num_pattern, vector<Value>(3)));
    _gate_value_array_frame_ids = vector<vector<vector<int>>>(_num_net,
                                                              vector<vector<int>>(num_pattern, vector<int>(3)));

}



bool Simulation::CompareLogicSimPo(const vector<vector<Value>> &serial_patterns_po,
                                   size_t pattern_id, size_t logic_array_id) {
    bool success = true;
    Value serial_logic_sim_po_result;
    Value correct_po_result;

    // cout << "compare pattern id" << pattern_id << endl;
    int store_frame_id = 0;
    for (int po_id = 0; po_id < serial_patterns_po[pattern_id].size(); ++po_id) {
        auto po_gate_id = _po[po_id]->GetId();
        correct_po_result = serial_patterns_po[pattern_id][po_id];
        store_frame_id = _gate_value_array_frame_ids[po_gate_id][pattern_id][logic_array_id];
        serial_logic_sim_po_result = _logic_array[po_gate_id][pattern_id][store_frame_id];
        if (serial_logic_sim_po_result != correct_po_result) {
#ifdef DEBUG
            cout << "logic sim po  id " << po_id << " gate id " << po_gate_id << " gate fanin name"
                 << _po[po_id]->GetFanin(0)->GetName();
            cout << " bit0 " << serial_logic_sim_po_result.bit0 << " bit1 " << serial_logic_sim_po_result.bit1 << endl;
            cout << "correct_po_result ";
            cout << " bit0 " << correct_po_result.bit0 << " bit1 " << correct_po_result.bit1 << endl;
#endif
            success = false;
        }
    }

    return success;
}

bool Simulation::CompareLogicSimScanChain(const vector<vector<vector<Value>>> &unload_values,
                                          size_t pattern_id, size_t logic_array_id) {
    bool success = true;
    Value serial_logic_sim_result;
    Value correct_dff_result;
    size_t dff_index = 0;
    int store_frame_id = 0;
    for (size_t i = 0; i < _scan_chains.size(); i++) {
        for (size_t j = 0; j < _scan_chains[i].size(); j++) {
            auto dff_gptr = _scan_chains[i][j];
            correct_dff_result = unload_values[pattern_id][i][j];
            store_frame_id = _gate_value_array_frame_ids[dff_gptr->GetId()][pattern_id][logic_array_id];
            serial_logic_sim_result = _logic_array[dff_gptr->GetId()][pattern_id][store_frame_id];
            if (serial_logic_sim_result != correct_dff_result) {
#ifdef DEBUG
                cout << "logic sim dff  gate id " << dff_gptr->GetId() << " name " << dff_gptr->GetName();
                cout << " bit0 " << serial_logic_sim_result.bit0 << " bit1 " << serial_logic_sim_result.bit1 << endl;
                cout << "correct_po_result ";
                cout << " bit0 " << correct_dff_result.bit0 << " bit1 " << correct_dff_result.bit1 << endl;
#endif
                success = false;
            }
            dff_index++;

        }
    }


    return success;
}

void Simulation::ConstructDffMater(int num_word) {
    _dff_master_logic_array = vector<vector<Value>>(_dff_gates.size(), vector<Value>(num_word));

}

void Simulation::PrintSerialScanChainsValue(size_t pattern_id, size_t frame_id) {
    for (auto scan_chain: _scan_chains) {
        for (auto dff_gptr : scan_chain) {
            cout << dff_gptr->GetName();
            int store_value_id = _gate_value_array_frame_ids[dff_gptr->GetId()][pattern_id][frame_id];
            Value dff_value = _logic_array[dff_gptr->GetId()][pattern_id][store_value_id];
            if (dff_value.bit0 == 0 && dff_value.bit1 == 1) {
                cout << " 0 " << endl;
            } else if (dff_value.bit0 == 1 && dff_value.bit1 == 0) {
                cout << " 1 " << endl;
            } else {
                cout << " X " << endl;
            }
        }
    }
}

bool Simulation::SingleFaultSim(vector<Fault *>& fsimlist,
                                EventContainer *events,
                                size_t start_faults_id,
                                size_t end_faults_id) {
    Value value1;
    Value value0;
    Value valuez;
    Value valuex;


    vector<Value> fault_array(_num_net);
    vector<bool>  fault_mark(_num_net);
    vector<Value> dff_master_value(_dff_gates.size());
    bool    diff;
    int     total_count = 0;
    vector<pair<int, int>> dff_master_ids;

    for (int fault_id = start_faults_id; fault_id < end_faults_id; ++fault_id) {
        total_count ++;
        if(total_count == 100 || fault_id == end_faults_id -1){
            _mutex.lock();
            _total_process_fault += total_count;
            double process_fault_percentage = ((double)_total_process_fault / fsimlist.size()) * 100;
            cout << "Processed Faults: " << setprecision(4) << process_fault_percentage <<"%" <<endl;
            _mutex.unlock();
            total_count = 0;
        }

        diff = false;
        Fault *fptr = fsimlist[fault_id];
        Gate  *fgate = fptr->GetFaultGate();
        Gate  *fanout;
        if (fptr->GetFaultStatus() == DETECTED)
            continue;

        vector<Gate *> fault_cone;
        queue<Gate *> bfs_que;
        unordered_set<Gate *> bfs_mark;
        bfs_que.push(fgate);
        while (!bfs_que.empty()) {
            auto front = bfs_que.front();
            bfs_que.pop();
            fault_cone.push_back(front);

            if(front->GetLogicType() == G_DFF){
                continue;
            }

            for (auto fo : front->GetAllFanouts()) {
                if (!bfs_mark.count(fo)) {
                    bfs_mark.insert(fo);
                    bfs_que.push(fo);
                }
            }
        }
        for (int pattern_id = 0; pattern_id < _pi_value_size; ++pattern_id) {
            if(!_is_parallel_pattern){
                value0.SetSerial0();
                value1.SetSerial1();
            }else{
                if(pattern_id == _pi_value_size - 1){
                    value0.SetParallel0(_last_pattern_bit_num);
                    value1.SetParallel1(_last_pattern_bit_num);
                }else{
                    value0.SetParallel0(SIZE_OF_PACKET);
                    value1.SetParallel1(SIZE_OF_PACKET);
                }
            }
            if (fptr->GetFaultStatus() == DETECTED) {
                events->clear();
                break;
            }


            for (auto gate : fault_cone) {
                fault_mark[gate->GetId()] = false;
                for (auto fi : gate->GetAllFanins()) {
                    fault_mark[fi->GetId()] = false;
                }
                if( gate->GetLogicType() == G_DFF){
                    auto gate_id = gate->GetId();
                    int dff_master_id = _dff_gate_id_to_master_map[gate_id];
                    auto store_value_frame_id = _gate_value_array_frame_ids[gate_id][pattern_id][0];
                    auto dff_slave_value = _logic_array[gate_id][pattern_id][store_value_frame_id];
                    dff_master_value[dff_master_id] = dff_slave_value;
                }

            }
//            for(auto &dff_master : dff_master_value){
//                dff_master.SetParallelX(SIZE_OF_PACKET);
//            }

            fault_mark[fgate->GetId()] = 1;//set as fault propagating net.
            Value inject_fault_value;
            //inject fault.
            if (fptr->GetFaultType() == SA0) {
                inject_fault_value = value0;
            } else {
                inject_fault_value = value1;
            }
            for (int frame = 0; frame < 3; frame++) {
                if (fptr->GetFaultStatus() == DETECTED) {
                    events->clear();
                    break;
                }
                diff = UpdateFsimGateValue(fgate, inject_fault_value, pattern_id, frame, fault_array, fault_mark, events);
                if (fgate->GetLogicType() == G_PO && diff) {
                    fptr->SetFaultStatus(DETECTED);
                    if(fptr->GetFaultEqv() != "--"){
                        fptr->SetFaultEqv("DT");
                    }
                }
                Gate *active_gptr = nullptr;
                vector<int> active_words;
                active_words.push_back(pattern_id);
                events->next(active_gptr, active_words);
                vector<Gate*> active_dff;
                while (active_gptr) {
                    if (fptr->GetFaultStatus() == DETECTED) {
                        events->clear();
                        break;
                    }
//                    if(frame == 0 && active_gptr ->GetLogicType() == G_DFF){
//                        auto gate_id = active_gptr->GetId();
//                        int dff_master_id = _dff_gate_id_to_master_map[gate_id];
//                        auto store_value_frame_id = _gate_value_array_frame_ids[gate_id][pattern_id][0];
//                        auto dff_slave_value = _logic_array[gate_id][pattern_id][store_value_frame_id];
//                        dff_master_value[dff_master_id] = dff_slave_value;
//                    }
                    diff = EvalGateFSim(active_gptr, pattern_id, frame, events, fault_mark, fault_array,
                                        dff_master_value);
                    // for the full scan circuit
                    // partial scan circuit contain nonscan dff, not all G_DFF are G_PPO
                    if ((active_gptr->GetLogicType() == G_PO || active_gptr->GetLogicType() == G_DFF) && diff) {
                        fptr->SetFaultStatus(DETECTED);
                        if(fptr->GetFaultEqv() != "--"){
                            fptr->SetFaultEqv("DT");
                        }
                        break;
                    }
                    if(active_gptr->GetLogicType() == G_DFF && frame < 2){
                        auto gate_id = active_gptr->GetId();
                        int dff_master_id = _dff_gate_id_to_master_map[gate_id];
                        Value master_hold_value;
                        master_hold_value = dff_master_value[dff_master_id];
                        auto store_value_frame_id = _gate_value_array_frame_ids[gate_id][pattern_id][frame + 1];
                        auto next_frame_slave_value = _logic_array[gate_id][pattern_id][store_value_frame_id];
                        if(next_frame_slave_value!= master_hold_value){
                            active_dff.push_back(active_gptr);
                        }
                    }
                    events->next(active_gptr, active_words);
                }
                for(auto dff: active_dff){
                    events->add(dff, pattern_id);
                }
                active_dff.clear();
            }


        }

    }
    return true;
}

bool Simulation::EvalGateFSim(Gate *gptr, int word_id, int frame_id, EventContainer *events,
                              vector<bool> &fault_mark, vector<Value> &fault_array,
                              vector<Value> &dff_master_value) {
    bool diff = false;
    unsigned int type = gptr->GetLogicType();

    int fanin_size = gptr->GetFaninsSize();
    uint64_t w0, w1;
    Value new_value;
    vector<uint64_t> v0(4, 0);
    vector<uint64_t> v1(4, 0);
    Value logic_value;
    int store_value_frame_id = 0;
    assert(fanin_size > 0);
    switch (type) {
        case G_PO:
        case G_BUF:
        case G_BUF_ASSGIN:
        case G_STEM: {
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                new_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                new_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_NOT: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            new_value.bit0 = old_value.bit1;
            new_value.bit1 = old_value.bit0;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_AND: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            uint64_t a0 = old_value.bit0;
            uint64_t a1 = old_value.bit1;
            for (int fi = 1; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    old_value = fault_array[gptr->GetFanin(fi)->GetId()];
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    old_value = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                }
                uint64_t b0 = old_value.bit0;
                uint64_t b1 = old_value.bit1;
                w0 = a0 & b0;
                w1 = a1 | b1;
                a0 = w0;
                a1 = w1;
            }
            new_value.bit0 = a0;
            new_value.bit1 = a1;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_NAND: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            uint64_t a0 = old_value.bit0;
            uint64_t a1 = old_value.bit1;
            for (int fi = 1; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    old_value = fault_array[gptr->GetFanin(fi)->GetId()];
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    old_value = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                }
                uint64_t b0 = old_value.bit0;
                uint64_t b1 = old_value.bit1;
                w0 = a0 & b0;
                w1 = a1 | b1;
                a0 = w0;
                a1 = w1;
            }
            new_value.bit0 = a1;
            new_value.bit1 = a0;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_OR: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            uint64_t a0 = old_value.bit0;
            uint64_t a1 = old_value.bit1;
            for (int fi = 1; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    old_value = fault_array[gptr->GetFanin(fi)->GetId()];
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    old_value = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                }
                uint64_t b0 = old_value.bit0;
                uint64_t b1 = old_value.bit1;
                w0 = a0 | b0;
                w1 = a1 & b1;
                a0 = w0;
                a1 = w1;
            }
            new_value.bit0 = a0;
            new_value.bit1 = a1;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_NOR: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            uint64_t a0 = old_value.bit0;
            uint64_t a1 = old_value.bit1;
            for (int fi = 1; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    old_value = fault_array[gptr->GetFanin(fi)->GetId()];
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    old_value = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                }
                uint64_t b0 = old_value.bit0;
                uint64_t b1 = old_value.bit1;
                w0 = a0 | b0;
                w1 = a1 & b1;
                a0 = w0;
                a1 = w1;
            }
            new_value.bit0 = a1;
            new_value.bit1 = a0;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_XOR: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            uint64_t a0 = old_value.bit0;
            uint64_t a1 = old_value.bit1;
            for (int fi = 1; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    old_value = fault_array[gptr->GetFanin(fi)->GetId()];
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    old_value = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                }
                uint64_t b0 = old_value.bit0;
                uint64_t b1 = old_value.bit1;
                w0 = ((a1 & b0) | (a0 & b1));
                w1 = ((a1 & b1) | (a0 & b0));
                a0 = w0;
                a1 = w1;
            }
            new_value.bit0 = a0;
            new_value.bit1 = a1;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_XNOR: {
            Value old_value;
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                old_value = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                old_value = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }
            uint64_t a0 = old_value.bit0;
            uint64_t a1 = old_value.bit1;
            for (int fi = 1; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    old_value = fault_array[gptr->GetFanin(fi)->GetId()];
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    old_value = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id];
                }
                uint64_t b0 = old_value.bit0;
                uint64_t b1 = old_value.bit1;
                w0 = ((a1 & b0) | (a0 & b1));
                w1 = ((a1 & b1) | (a0 & b0));
                a0 = w0;
                a1 = w1;
            }
            new_value.bit0 = a1;
            new_value.bit1 = a0;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_MUX: {
            Value in0, in1, sel;
            if (fault_mark[gptr->GetFanin(1)->GetId()]) {
                in0 = fault_array[gptr->GetFanin(1)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(1)->GetId()][word_id][frame_id];
                in0 = _logic_array[gptr->GetFanin(1)->GetId()][word_id][store_value_frame_id];
            }

            if (fault_mark[gptr->GetFanin(2)->GetId()]) {
                in1 = fault_array[gptr->GetFanin(2)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(2)->GetId()][word_id][frame_id];
                in1 = _logic_array[gptr->GetFanin(2)->GetId()][word_id][store_value_frame_id];
            }
            if (fault_mark[gptr->GetFanin(0)->GetId()]) {
                sel = fault_array[gptr->GetFanin(0)->GetId()];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(0)->GetId()][word_id][frame_id];
                sel = _logic_array[gptr->GetFanin(0)->GetId()][word_id][store_value_frame_id];
            }


            uint64_t se_not0 = sel.bit1;
            uint64_t se_not1 = sel.bit0;
            new_value.bit0 = ((se_not0 & in0.bit0) | (sel.bit0 & in1.bit0));;
            new_value.bit1 = ((se_not1 | in0.bit1) & (sel.bit1 | in1.bit1));;
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        case G_DFF: {



            uint64_t set0, set1, reset0, reset1, clock0, clock1, data_in0, data_in1;

            assert(fanin_size == 4);
            for (int fi = 0; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    v0[fi] = fault_array[gptr->GetFanin(fi)->GetId()].bit0;
                    v1[fi] = fault_array[gptr->GetFanin(fi)->GetId()].bit1;
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    v0[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit0;
                    v1[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit1;
                }
            }

            set0 = v0[0];
            set1 = v1[0];

            reset0 = v0[1];
            reset1 = v1[1];

            clock0 = v0[2];
            clock1 = v1[2];

            data_in0 = v0[3];
            data_in1 = v1[3];
            int dff_gate_id = gptr->GetId();
            assert(_dff_gate_id_to_master_map.count(dff_gate_id));
            int dff_master_id = _dff_gate_id_to_master_map[dff_gate_id];

            Value master_hold_value;
            master_hold_value = dff_master_value[dff_master_id];
            Value master_new_value;


            master_new_value.bit0 = ((~clock0) & clock1 & data_in0) | ((~clock1) & clock0 & master_hold_value.bit0);
            master_new_value.bit1 = ((~clock0) & clock1 & data_in1) | ((~clock1) & clock0 & master_hold_value.bit1);

            master_new_value.bit0 = ((~set0) & set1 & master_new_value.bit0) | ((~set1) & set0);
            master_new_value.bit1 = ((~set0) & set1 & master_new_value.bit1);


            master_new_value.bit0 = ((~reset0) & reset1 & master_new_value.bit0);
            master_new_value.bit1 = ((~reset0) & reset1 & master_new_value.bit1) | ((~reset1) & reset0);


            Value slave_hold_value;
            if (fault_mark[dff_gate_id]) {
                slave_hold_value = fault_array[dff_gate_id];
            } else {
                auto pre_frame_id = frame_id;
                if(frame_id > 0){
                    pre_frame_id = frame_id -1;
                }
                store_value_frame_id = _gate_value_array_frame_ids[dff_gate_id][word_id][pre_frame_id];
                slave_hold_value = _logic_array[dff_gate_id][word_id][store_value_frame_id];
            }
            Value slave_new_value;



            slave_new_value.bit0 =
                    ((~clock1) & clock0 & master_hold_value.bit0) | ((~clock0) & clock1 & slave_hold_value.bit0);
            slave_new_value.bit1 =
                    ((~clock1) & clock0 & master_hold_value.bit1) | ((~clock0) & clock1 & slave_hold_value.bit1);


            slave_new_value.bit0 = ((~set0) & set1 & slave_new_value.bit0) | ((~set1) & set0);
            slave_new_value.bit1 = ((~set0) & set1 & slave_new_value.bit1);


            slave_new_value.bit0 = ((~reset0) & reset1 & slave_new_value.bit0);
            slave_new_value.bit1 = ((~reset0) & reset1 & slave_new_value.bit1) | ((~reset1) & reset0);

            dff_master_value[dff_master_id] = master_new_value;
            diff = UpdateFsimGateValue(gptr, slave_new_value, word_id, frame_id, fault_array, fault_mark, events);

            break;
        }
        case G_DLAT: {

            uint64_t set0, set1, reset0, reset1, clock0, clock1, data_in0, data_in1;
            assert(fanin_size == 4);
            for (int fi = 0; fi < fanin_size; fi++) {
                if (fault_mark[gptr->GetFanin(fi)->GetId()]) {
                    v0[fi] = fault_array[gptr->GetFanin(fi)->GetId()].bit0;
                    v1[fi] = fault_array[gptr->GetFanin(fi)->GetId()].bit1;
                } else {
                    store_value_frame_id = _gate_value_array_frame_ids[gptr->GetFanin(
                            fi)->GetId()][word_id][frame_id];
                    v0[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit0;
                    v1[fi] = _logic_array[gptr->GetFanin(fi)->GetId()][word_id][store_value_frame_id].bit1;

                }
            }

            set0 = v0[0];
            set1 = v1[0];

            reset0 = v0[1];
            reset1 = v1[1];

            clock0 = v0[2];
            clock1 = v1[2];

            data_in0 = v0[3];
            data_in1 = v1[3];
            int dlat_gate_id = gptr->GetId();

            Value hold_value;
            if (fault_mark[dlat_gate_id]) {
                hold_value = fault_array[dlat_gate_id];
            } else {
                store_value_frame_id = _gate_value_array_frame_ids[dlat_gate_id][word_id][frame_id];
                hold_value = _logic_array[dlat_gate_id][word_id][store_value_frame_id];
            }

            new_value.bit0 = ((~clock0) & clock1 & hold_value.bit0) | ((~clock1) & clock0 & data_in0);
            new_value.bit1 = ((~clock0) & clock1 & hold_value.bit1) | ((~clock1) & clock0 & data_in1);

            new_value.bit0 = ((~set0) & set1 & new_value.bit0) | ((~set1) & set0);
            new_value.bit1 = ((~set0) & set1 & new_value.bit1);

            new_value.bit0 = ((~reset0) & reset1 & new_value.bit0);
            new_value.bit1 = ((~reset0) & reset1 & new_value.bit1) | ((~reset1) & reset0);
            diff = UpdateFsimGateValue(gptr, new_value, word_id, frame_id, fault_array, fault_mark, events);
            break;
        }
        default:
            string msg = "not support logic type" + to_string(type);
            cerr << Errors::ErrorsMsg(ErrorType::FSIM_RUN_FAILED, msg) << endl;
            assert(false);

    }
    return diff;

}

bool
Simulation::UpdateFsimGateValue(Gate *gptr, Value new_value, size_t word_id, int frame_id, vector<Value> &fault_array,
                                vector<bool> &fault_mark, EventContainer *events) {
    bool diff = false;

    fault_array[gptr->GetId()] = new_value;
    int store_value_frame_id = _gate_value_array_frame_ids[gptr->GetId()][word_id][frame_id];
    Value logic_value = _logic_array[gptr->GetId()][word_id][store_value_frame_id];

    uint64_t  bit0_diff =  logic_value.bit0 ^ new_value.bit0;
    uint64_t  bit1_diff =  logic_value.bit1 ^ new_value.bit1;
    uint64_t  diff_bit_mask = bit0_diff ^ bit1_diff;



    if(_is_parallel_pattern){
        diff = logic_value != new_value && (diff_bit_mask == 0 || ((bit0_diff | diff_bit_mask) != diff_bit_mask) || ((bit1_diff | diff_bit_mask) != diff_bit_mask)  );
    }else{
        diff = logic_value != new_value && ((logic_value.bit0 ^ logic_value.bit1) != 0) &&((new_value.bit0 ^ new_value.bit1) != 0);
    }

    if (diff) {

        fault_mark[gptr->GetId()] = true;
        AddActiveGateToEvents(gptr, events, word_id);
    }

    return diff;

}

void Simulation::GetSerialPattern() {
    _is_parallel_pattern = false;
    _pi_value       = _pattern_reader.GetSerialPatternsPi();
    _po_value       = _pattern_reader.GetSerialPatternsPo();
    _load_value     = _pattern_reader.GetSerialLoadValue();
    _unload_value   = _pattern_reader.GetSerialUnloadValue();
    _pattern_clock_value = _pattern_reader.GetSerialPatternClockValue();
    _num_pattern    = _pattern_reader.GetPatternNums();
    _pi_value_size  = _pi_value.size();
}

void Simulation::GetParallelPattern() {
    _is_parallel_pattern = true;
    _pi_value       = _pattern_reader.GetParallelPatternsPi();
    _po_value       = _pattern_reader.GetParallelPatternsPo();
    _load_value     = _pattern_reader.GetParallelLoadValue();
    _unload_value   = _pattern_reader.GetParallelUnloadValue();
    _pattern_clock_value = _pattern_reader.GetParallelPatternClockValues();
    _num_pattern    = _pattern_reader.GetPatternNums();
    _pi_value_size  = _pi_value.size();
}




